def Tracer(aClass):
    class wrapper:
        def __init__(self, *args, **kwargs):
            self.fetches = 0
            self.wrapped = aClass(*args, **kwargs)

        def __getattr__(self, name):
            print('Trace:', name)
            self.fetches += 1
            return getattr(self.wrapped, name)
    return wrapper


if __name__ == '__main__':
    @Tracer
    class Spam:
        def display(self):
            print('Spam!'*8)

    @Tracer
    class Person:
        def __init__(self, name, hours, rate):
            self.name = name
            self.hours = hours
            self.rate = rate

        def pay(self):
            return self.hours*self.rate

    food = Spam()  # Triggers Wrapper()
    food.display()  # Triggers __getattr__
    print([food.fetches])
    bob = Person('Bob', 40, 50)  # bob is really a Wrapper
    print(bob.name)  # Wrapper embeds a Person
    print(bob.pay())
    print('')
    sue = Person('Sue', rate=100, hours=60)  # sue is a different Wrapper
    print(sue.name)  # with a different Person
    print(sue.pay())
    print(bob.name)  # bob has different state
    print(bob.pay())
    print([bob.fetches, sue.fetches])  # Wrapper attrs not traced
